using UnityEditor;
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
  
public static class ExposeProperties
{
        public static void Expose(PropertyField[] properties)
        {
                var emptyOptions = new GUILayoutOption[0];
                EditorGUILayout.BeginVertical(emptyOptions);
                foreach (PropertyField field in properties)
                {
                        EditorGUILayout.BeginHorizontal(emptyOptions);
                        if (field.Type == SerializedPropertyType.Integer)
                        {
                                var oldValue = (int)field.GetValue();
                                var newValue = EditorGUILayout.IntField(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.Float)
                        {
                                var oldValue = (float)field.GetValue();
                                var newValue = EditorGUILayout.FloatField(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.Boolean)
                        {
                                var oldValue = (bool)field.GetValue();
                                var newValue = EditorGUILayout.Toggle(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.String)
                        {
                                var oldValue = (string)field.GetValue();
                                var newValue = EditorGUILayout.TextField(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.Vector2)
                        {
                                var oldValue = (Vector2)field.GetValue();
                                var newValue = EditorGUILayout.Vector2Field(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.Vector3)
                        {
                                var oldValue = (Vector3)field.GetValue();
                                var newValue = EditorGUILayout.Vector3Field(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.Enum)
                        {
                                var oldValue = (Enum)field.GetValue();
                                var newValue = EditorGUILayout.EnumPopup(field.Name, oldValue, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        else if (field.Type == SerializedPropertyType.ObjectReference)
                        {
                                UnityEngine.Object oldValue = (UnityEngine.Object)field.GetValue();
                                UnityEngine.Object newValue = EditorGUILayout.ObjectField(field.Name, oldValue, field.Info.PropertyType, emptyOptions);
                                if (oldValue != newValue)
                                        field.SetValue(newValue);
                        }
                        EditorGUILayout.EndHorizontal();
                }
                EditorGUILayout.EndVertical();
        }
  
        public static PropertyField[] GetProperties(object obj)
        {
                var fields = new List<PropertyField>();
  
                PropertyInfo[] infos = obj.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
  
                foreach (PropertyInfo info in infos)
                {
                        if (!(info.CanRead && info.CanWrite))
                                continue;
  
                        object[] attributes = info.GetCustomAttributes(true);
  
                        bool isExposed = false;
                        foreach (object o in attributes)
                                if (o.GetType() == typeof(ExposePropertyAttribute))
                        {
                                isExposed = true;
                                break;
                        }
                        if (!isExposed)
                                continue;
  
                        var type = SerializedPropertyType.Integer;
                        if (PropertyField.GetPropertyType(info, out type))
                        {
                                var field = new PropertyField(obj, info, type);
                                fields.Add(field);
                        }
                }
  
                return fields.ToArray();
        }
}
  
public class PropertyField
{
        object obj;
        PropertyInfo info;
        SerializedPropertyType type;
  
        MethodInfo getter;
        MethodInfo setter;
  
        public PropertyInfo Info
        {
                get { return info; }
        }
  
        public SerializedPropertyType Type
        {
                get { return type; }
        }
  
        public String Name
        {
                get { return ObjectNames.NicifyVariableName(info.Name); }
        }
  
        public PropertyField(object obj, PropertyInfo info, SerializedPropertyType type)
        {
                this.obj = obj;
                this.info = info;
                this.type = type;
  
                getter = this.info.GetGetMethod();
                setter = this.info.GetSetMethod();
        }
  
        public object GetValue() { return getter.Invoke(obj, null); }
        public void SetValue(object value) { setter.Invoke(obj, new[] {value}); }
  
        public static bool GetPropertyType(PropertyInfo info, out SerializedPropertyType propertyType)
        {
                Type type = info.PropertyType;
                propertyType = SerializedPropertyType.Generic;
                if (type == typeof(int))
                        propertyType = SerializedPropertyType.Integer;
                else if (type == typeof(float))
                        propertyType = SerializedPropertyType.Float;
                else if (type == typeof(bool))
                        propertyType = SerializedPropertyType.Boolean;
                else if (type == typeof(string))
                        propertyType = SerializedPropertyType.String;
                else if (type == typeof(Vector2))
                        propertyType = SerializedPropertyType.Vector2;
                else if (type == typeof(Vector3))
                        propertyType = SerializedPropertyType.Vector3;
                else if (type.IsEnum)
                        propertyType = SerializedPropertyType.Enum;
                else if (typeof(MonoBehaviour).IsAssignableFrom(type))
                        propertyType = SerializedPropertyType.ObjectReference;
                return propertyType != SerializedPropertyType.Generic;
        }
}